package com.gwt.client.ui.widget.editor;

import java.util.Set;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.shared.EventBus;
import com.google.gwt.requestfactory.client.RequestFactoryEditorDriver;
import com.google.gwt.requestfactory.shared.Receiver;
import com.google.gwt.requestfactory.shared.Request;
import com.google.gwt.requestfactory.shared.RequestContext;
import com.google.gwt.requestfactory.shared.Violation;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DialogBox;
import com.gwt.client.event.EditBeerEvent;
import com.gwt.shared.BeerProxy;
import com.gwt.shared.BeerTableRequestFactory;
import com.gwt.shared.BeerTableRequestFactory.BeerRequest;

public class BeerEditorWorkflow {
	interface Binder extends UiBinder<DialogBox, BeerEditorWorkflow> {
		Binder BINDER = GWT.create(Binder.class);
	}

	interface Driver extends RequestFactoryEditorDriver<BeerProxy, BeerEditor> {

	}

	@UiField
	DialogBox dialog;

	@UiField(provided = true)
	BeerEditor beerEditor;

	@UiField
	Button saveButton;

	@UiField
	Button cancelButton;

	private Driver beerDriver;
	private BeerProxy beer;
	private BeerTableRequestFactory requestFactory;

	private BeerEditorWorkflow(BeerTableRequestFactory requestFactory, BeerProxy beer) {
		this.requestFactory = requestFactory;
		this.beer = beer;

		BeerStyleEditor styleEditor = new BeerStyleEditor();
		beerEditor = new BeerEditor(styleEditor);

		Binder.BINDER.createAndBindUi(this);
	}

	public static void register(EventBus eventBus, final BeerTableRequestFactory requestFactory) {
		eventBus.addHandler(EditBeerEvent.TYPE, new EditBeerEvent.Handler() {

			@Override
			public void editBeer(BeerProxy beer, RequestContext requestContext) {
				new BeerEditorWorkflow(requestFactory, beer).edit(requestContext);
			}
		});
	}

	@UiHandler("cancelButton")
	void onCancel(ClickEvent event) {
		dialog.hide();
	}

	@UiHandler("saveButton")
	void onSave(ClickEvent event) {
		RequestContext context = beerDriver.flush();

		if (beerDriver.hasErrors()) {
			Window.alert("Invalid Entries exist!");
			return;
		}

		context.fire(new Receiver<Void>() {

			@Override
			public void onSuccess(Void response) {
				dialog.hide();
				Window.alert("Save Successful!");
			}

			@Override
			public void onViolation(Set<Violation> errors) {
				Window.alert("You Screwed Something Up!");
				beerDriver.setViolations(errors);
			}
		});
	}

	private void edit(RequestContext context) {
		beerDriver = GWT.create(Driver.class);
		beerDriver.initialize(requestFactory, beerEditor);

		if (context == null) {
			fetchAndEdit();
			return;
		}

		beerDriver.edit(beer, context);
		beerEditor.focus();
		dialog.center();
	}

	private void fetchAndEdit() {
		Request<BeerProxy> fetchRequest = requestFactory.find(beer.stableId());

		fetchRequest.with(beerDriver.getPaths());

		fetchRequest.to(new Receiver<BeerProxy>() {

			@Override
			public void onSuccess(BeerProxy beer) {
				BeerEditorWorkflow.this.beer = beer;

				BeerRequest context = requestFactory.beerRequest();

				edit(context);

				context.persist().using(beer);
			}
		}).fire();
	}
}
